package com.sjsu.cmpe239.evaluationTests;

import java.io.File;
import java.io.IOException;
import java.util.List;

import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.common.Weighting;
import org.apache.mahout.cf.taste.eval.IRStatistics;
import org.apache.mahout.cf.taste.eval.RecommenderBuilder;
import org.apache.mahout.cf.taste.eval.RecommenderEvaluator;
import org.apache.mahout.cf.taste.eval.RecommenderIRStatsEvaluator;
import org.apache.mahout.cf.taste.impl.eval.AverageAbsoluteDifferenceRecommenderEvaluator;
import org.apache.mahout.cf.taste.impl.eval.GenericRecommenderIRStatsEvaluator;
import org.apache.mahout.cf.taste.impl.eval.RMSRecommenderEvaluator;
import org.apache.mahout.cf.taste.impl.model.file.FileDataModel;
import org.apache.mahout.cf.taste.impl.model.jdbc.MySQLJDBCDataModel;
import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
import org.apache.mahout.cf.taste.impl.recommender.GenericItemBasedRecommender;

import org.apache.mahout.cf.taste.impl.similarity.CachingUserSimilarity;
import org.apache.mahout.cf.taste.impl.similarity.EuclideanDistanceSimilarity;
import org.apache.mahout.cf.taste.impl.similarity.LogLikelihoodSimilarity;
import org.apache.mahout.cf.taste.impl.similarity.PearsonCorrelationSimilarity;
import org.apache.mahout.cf.taste.impl.similarity.SpearmanCorrelationSimilarity;
import org.apache.mahout.cf.taste.impl.similarity.TanimotoCoefficientSimilarity;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.model.JDBCDataModel;
import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.apache.mahout.cf.taste.recommender.Recommender;
import org.apache.mahout.cf.taste.similarity.ItemSimilarity;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;
import org.junit.BeforeClass;
import org.junit.Test;

import com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

public class ItemBasedRecommenderEvalatorTest {
	// TODO Auto-generated method stub
	//static DataModel model = buildDataModel();
	static FileDataModel model;

	@BeforeClass
	public static void buildDataModel() throws IOException {
		MysqlDataSource dataSource = new MysqlConnectionPoolDataSource();
		dataSource.setServerName("localhost");
		dataSource.setUser("root");
		dataSource.setPassword("");
		dataSource.setDatabaseName("239db");

		model = new FileDataModel(new File("d:/ratings.csv"));

	}
	/*
	 * UserSimilarity : PearsonCorrelationSimilarity
	 * UserNeighborhood:NearestNUserNeighborhood
	 */
	@Test
	public  void evaluateUserBasedRecWithPearson() throws TasteException {

		// Start: evaluate with Average absolute difference
		RecommenderEvaluator evaluator = new AverageAbsoluteDifferenceRecommenderEvaluator();
		RecommenderBuilder builder = new RecommenderBuilder() {
			@Override
			public Recommender buildRecommender(DataModel model)
					throws TasteException {
				ItemSimilarity similarity = new PearsonCorrelationSimilarity(
						model);
				
				return new GenericItemBasedRecommender
						(model,
						similarity);
			}
		};

		double score = evaluator.evaluate(builder, null, model, 0.9, 1.0);
		System.out
		.println("\nevaluateUserBasedRecWithPearson");
		System.out
				.println("AverageAbsoluteDifferenceEvaluator score: " + score);

		// Start: evaluate with RMSRecommenderEvaluator
		evaluator = new RMSRecommenderEvaluator();
		score = evaluator.evaluate(builder, null, model, 0.9, 1.0);
		System.out.println("RMSEvaluator score: " + score);

		/*
		 * RecommenderIRStatsEvaluator irStatsEvaluator = new
		 * GenericRecommenderIRStatsEvaluator(); IRStatistics stats =
		 * irStatsEvaluator.evaluate(builder, null, model, null, 2, 1.0, 1.0);
		 * System.out.println("IRStatistics precision: " +
		 * stats.getPrecision()); System.out.println("IRStatistics recall: " +
		 * stats.getRecall());
		 */

	}

	/*
	 * UserSimilarity : PearsonCorrelationSimilarity,weighting
	 * UserNeighborhood:NearestNUserNeighborhood
	 */
	@Test
	public  void evaluateUserBasedRecWithPearsonWithWeighting() throws TasteException {

		// Start: evaluate with Average absolute difference
		RecommenderEvaluator evaluator = new AverageAbsoluteDifferenceRecommenderEvaluator();
		RecommenderBuilder builder = new RecommenderBuilder() {
			@Override
			public Recommender buildRecommender(DataModel model)
					throws TasteException {
				ItemSimilarity similarity = new PearsonCorrelationSimilarity(
						model,Weighting.WEIGHTED);
				
				return new GenericItemBasedRecommender
						(model,
						similarity);
			}
		};

		double score = evaluator.evaluate(builder, null, model, 0.9, 1.0);
		System.out
		.println("\nevaluateUserBasedRecWithPearson");
		System.out
				.println("AverageAbsoluteDifferenceEvaluator score: " + score);

		// Start: evaluate with RMSRecommenderEvaluator
		evaluator = new RMSRecommenderEvaluator();
		score = evaluator.evaluate(builder, null, model, 0.9, 1.0);
		System.out.println("RMSEvaluator score: " + score);
	}

	/*
	 * UserSimilarity : EuclideanDistanceSimilarity, UserNeighborhood:
	 * NearestNUserNeighborhood
	 */
	@Test
	public  void evaluateUserBasedRecWithEuclidean()
			throws TasteException { // evaluate with Average absolute difference

		RecommenderEvaluator evaluator = new AverageAbsoluteDifferenceRecommenderEvaluator();
		RecommenderBuilder builder = new RecommenderBuilder() {
			@Override
			public Recommender buildRecommender(DataModel model)
					throws TasteException {
				ItemSimilarity similarity = new EuclideanDistanceSimilarity(
						model);
				
				return new GenericItemBasedRecommender(model,
						similarity);
			}
		};
		double score = evaluator.evaluate(builder, null, model, 0.9, 1.0);
		System.out
		.println("\nevaluateUserBasedRecWithEuclidean");
		System.out
				.println("AverageAbsoluteDifferenceEvaluator score: " + score);

		evaluator = new RMSRecommenderEvaluator(); // evaluate with
													// RMSRecommenderEvaluator
		score = evaluator.evaluate(builder, null, model, 0.9, 1.0);
		System.out.println("RMSEvaluator score: " + score);
	}

	/*
	 * UserSimilarity : EuclideanDistanceSimilarity,weighted
	 *  UserNeighborhood:
	 * NearestNUserNeighborhood
	 */
	@Test
	public  void evaluateUserBasedRecWithEuclideanWithWeighting()
			throws TasteException { // evaluate with Average absolute difference

		RecommenderEvaluator evaluator = new AverageAbsoluteDifferenceRecommenderEvaluator();
		RecommenderBuilder builder = new RecommenderBuilder() {
			@Override
			public Recommender buildRecommender(DataModel model)
					throws TasteException {
				ItemSimilarity similarity = new EuclideanDistanceSimilarity(
						model,Weighting.WEIGHTED);
				
				return new GenericItemBasedRecommender(model,
						similarity);
			}
		};
		double score = evaluator.evaluate(builder, null, model, 0.9, 1.0);
		System.out
		.println("\nevaluateUserBasedRecWithEuclidean");
		System.out
				.println("AverageAbsoluteDifferenceEvaluator score: " + score);

		evaluator = new RMSRecommenderEvaluator(); // evaluate with
													// RMSRecommenderEvaluator
		score = evaluator.evaluate(builder, null, model, 0.9, 1.0);
		System.out.println("RMSEvaluator score: " + score);
	}
	
	
	/*
	 * UserSimilarity : TanimotoCoefficientSimilarity, UserNeighborhood:
	 * NearestNUserNeighborhood
	 */
	@Test
	public  void evaluateUserBasedRecWithTanimoto() throws TasteException {

		RecommenderEvaluator evaluator = new AverageAbsoluteDifferenceRecommenderEvaluator();
		RecommenderBuilder builder = new RecommenderBuilder() {
			@Override
			public Recommender buildRecommender(DataModel model)
					throws TasteException {
				ItemSimilarity similarity = new TanimotoCoefficientSimilarity(
						model);
				
				return new GenericItemBasedRecommender(model,
						similarity);
			}
		};
		double score = evaluator.evaluate(builder, null, model, 0.9, 1.0); // evaluate
																			// with
																			// Average
																			// absolute
																			// difference
		System.out
				.println("======evaluateItemBasedRecWithTanimoto==============================================");
		System.out
				.println("AverageAbsoluteDifferenceEvaluator score: " + score);

		// /
		evaluator = new RMSRecommenderEvaluator();
		score = evaluator.evaluate(builder, null, model, 0.9, 1.0);// evaluate
																	// with
																	// RMSRecommenderEvaluator
		System.out.println("RMSEvaluator score: " + score);
	}

	/*
	 * ItemSimilarity : LogLikelihoodSimilarity 
	 */
	@Test
	public  void evaluateItemBasedRecWithLogLikelihoodSimilarity()
			throws TasteException {

		RecommenderEvaluator evaluator = new AverageAbsoluteDifferenceRecommenderEvaluator();
		RecommenderBuilder builder = new RecommenderBuilder() {
			@Override
			public Recommender buildRecommender(DataModel model)
					throws TasteException {
				ItemSimilarity similarity = new LogLikelihoodSimilarity(model);
				Recommender r = new GenericItemBasedRecommender(model,
						similarity);
				List<RecommendedItem> recommendations = r.recommend(3, 10);
				System.out.println("top 10 recommendations for user 3 :");
				for (RecommendedItem recommendation : recommendations) {
					System.out.println(recommendation);
				}
				return r;
			}
		};

		double score = evaluator.evaluate(builder, null, model, 0.9, 1.0); // evaluate
																			// with
																			// Average
																			// absolute
																			// difference
		System.out
				.println("====evaluateItemBasedRecWithLogLikelihoodSimilarity=====================================================");
		System.out
				.println("AverageAbsoluteDifferenceEvaluator score: " + score);

		// /
		evaluator = new RMSRecommenderEvaluator();
		score = evaluator.evaluate(builder, null, model, 0.9, 1.0);// evaluate
																	// with
																	// RMSRecommenderEvaluator
		System.out.println("RMSEvaluator score: " + score);
	}


}
